
/* Threads safe. FIFO queue. */

#include "common.h"

queue_t * queue_create()
{
	queue_t *q = mempool_alloc(sizeof(*q));
	if(!q) 
		return q;
	
	pthread_cond_init(&q->cond, NULL);
	pthread_mutex_init(&q->lock, NULL);
	INIT_LIST_HEAD(&q->list);
	q->count = 0;

	return q;
}

/* -1 failed; 0 success */
int queue_push(queue_t *queue, struct list_head *new)
{
	if(!queue) 
		return -1;
	if(!new)
		return -1;
	
	if(pthread_mutex_lock(&queue->lock))
		return -1;
	list_add_tail(new, &queue->list);
	queue->count++;
	pthread_mutex_unlock(&queue->lock);
	
	return 0;
}


struct list_head *queue_pop(queue_t *queue)
{
	if(!queue) 
		return NULL;
	if(list_empty(&queue->list))
		return NULL;
	struct list_head *res = NULL;

	pthread_mutex_lock(&queue->lock);
	if(list_empty(&queue->list)) {
		pthread_mutex_unlock(&queue->lock);
		return res;
	}
	struct list_head *p = queue->list.next;
	res = p;
	list_del_init(p);
	pthread_mutex_unlock(&queue->lock);

	return p;
}

int queue_length(queue_t *queue)
{
	if(!queue) 
		return 0;

	int length = 0;

	pthread_mutex_lock(&queue->lock);
	length = queue->count;
	pthread_mutex_unlock(&queue->lock);

	return length;
}

struct list_head *queue_head(queue_t *queue)
{
	if(!queue) 
		return NULL;
	if(list_empty(&queue->list))
		return NULL;

	struct list_head *retv = NULL;
	pthread_mutex_lock(&queue->lock);
	retv = queue->list.next;
	pthread_mutex_unlock(&queue->lock);
	return retv;
}

void queue_destroy(queue_t *queue)
{
	if(!queue)
		return;

	list_del_init(&queue->list);
	mempool_free(queue);
}
